package com.djhu.freepartner.web.control.aspect;

import com.djhu.freepartner.core.RestLog;
import com.djhu.freepartner.core.RestRsp;
import com.djhu.freepartner.core.Status;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

@Aspect
@Component
public class RestLogAspect {
    private static final Logger logger = LoggerFactory.getLogger(RestLogAspect.class);


    @Pointcut(value="(execution(public * com.djhu.freepartner.*.*.controller..*.*(..)) ||execution(public * com.djhu.freepartner.web.control.*.*(..)))")
    public void restLogPointcut(){
        return;
    }

    @Around(value = "restLogPointcut()")
    public Object doAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        RestLog log = new RestLog();
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        processLog(request,log);
        processLog(proceedingJoinPoint,log);

        RestRsp result = null;


        try {// obj之前可以写目标方法执行前的逻辑
            Object obj = proceedingJoinPoint.proceed();// 调用执行目标方法
            //如果返回值必须是Result
            if(obj instanceof RestRsp){
                result = (RestRsp) obj;
                log.setResult(result);
                log.setProcessTimeInMs(System.currentTimeMillis()-log.getStartTime());
                log.saveLog();
                return result;
            }else{
                logger.warn("Return value:"+obj.getClass().getName()+" is not instance of "+RestRsp.class.getName()+", won't save business log!");
                return obj;
            }

        } catch (Throwable throwable) {
            log.setExceptionClassName(throwable.getClass().getName());
            log.setExceptionMessage(throwable.getMessage());
            result = processExceptionResult(throwable);
            log.setResult(result);
            log.saveLog();
            throw throwable;
        }
//        log.setResult(result);
//        log.setProcessTimeInMs(System.currentTimeMillis()-log.getStartTime());
//        log.saveLog();
//        return result;
    }

    protected void processLog(HttpServletRequest request,RestLog log){
        //nginx 做代理，会把真实的对方ip放到header里面
        String realIP = request.getHeader("X-Real-IP");

        if(StringUtils.isEmpty(realIP)){
            log.setRemoteAddr(realIP);
        }else{
            log.setRemoteAddr(request.getRemoteAddr());
        }
        log.setLocalAddr(request.getLocalAddr());
        log.setLocalPort(request.getLocalPort());
        log.setUri(request.getRequestURI());
    }

    /**
     *
     * @param joinPoint
     * @param log
     */
    protected void processLog(ProceedingJoinPoint joinPoint, RestLog log){
        log.setProcessClass(joinPoint.getTarget().getClass().getName());
        log.setParameters(joinPoint.getArgs());
        log.setProcessMethod(joinPoint.getSignature().toString());
    }


//    /**
//     * 根据异常拼装返回的值
//     * @param t
//     * @return
//     */
//    protected static Result<Object> processExceptionResult(Throwable t ){
//        //TODO: 定制化业务异常
//        if(t instanceof ParseException){
//            return new Result<>(ResultEnum.USER_ARGS_TIME_YYYYMMDDHHMMSS_ERROR.getCode(),ResultEnum.USER_ARGS_TIME_YYYYMMDDHHMMSS_ERROR.getMsg());
//        }else if(t instanceof ServiceException){
//            ServiceException e = (ServiceException) t;
//            return new Result<>(e.getCode(),e.getMsg());
//        }else if(t instanceof MyBatisSystemException){
//            return new Result<>(ResultEnum.SERVICE_SQL_MYBATIS_EXECUTE_ERROR.getCode(),ResultEnum.SERVICE_SQL_MYBATIS_EXECUTE_ERROR.getMsg());
//        }
//        // TODO: mysql Exception
//        Result<Object> result = new Result<Object>(ResultEnum.SERVICE_UNKONW_ERROR);
//        result.setMsg(t.getClass().getName()+":"+t.getMessage());
//        return result;
 //   }

    protected static RestRsp processExceptionResult(Throwable t ){

        RestRsp result = new RestRsp(Status.SERVER_ERROR);
        return result;
    }



}
